/**
 * Create a window
 * @constructor
 * @param {Object} param
 * @param {Number} param.width 横幅
 * @param {Number} param.height 縦幅
 * @param {Number} param.x x座標
 * @param {Number} param.y y座標
 * @param {String} param.application 作成元のアプリケーションid
 * @param {String} param.title タイトル
 * @param {Node|joWindow} param.related 基準になるノードまたはjoWindowオブジェクト
 */
function joWindow(param){
	this.param = param;

	this.init();
}
joWindow.prototype = {

	/**
	 * ウィンドウの構造（XHTML）
	 * @type String
	 */
	constract: [
		'<div class="menubar">',
		'	<button class="button-close">x</button>',
		'	<button class="button-minimize">-</button>',
		'	<button class="button-maximize">+</button>',
		'	<div class="title">Untitled</div>',
		'</div>',
		'<div class="content"></div>',
		'<div class="statusbar">',
		'	<div class="resizer"></div>',
		'</div>',
		'<div class="dammy-wrapper"></div>', //non-activeなwindowにかぶせ、clickを効率よく処理するためのwrapper
	].join(''),
	
	/**
	 * 各要素のDOMの参照
	 * @type Object
	 */
	display: {},
	
	defaultTitle: 'Untitled',

	/**
	 * ウィンドウを初期化する<br>
	 * 処理項目が多いので, joWindowを継承するときには独自の初期化処理は init_self とすることを推奨
	 * @private
	 */
	init: function(){
		this._setRelatedPosition();
	
		this.display.window = joCore.Node.createNode('div', { 'class': 'window ' + this.param.application }, $('windows'));
		this.display.window.owner = this;
		this.display.window.innerHTML = this.constract;

		this.display.title = $C('title', this.display.window);
		this.display.content = $C('content', this.display.window);
		this.display.statusbar = $C('statusbar', this.display.window);
		this.display.menubar = $C('menubar', this.display.window);
		
		joCore.Node.addStyle(this.display.window, {
			width: this.param.width + 'px',
			height: this.param.height + 'px',
			'top': this.param.y + 'px',
			'left': this.param.x + 'px'
		});
		
		this.width = this.param.width;
		this.height = this.param.height;
		this.x = this.param.x;
		this.y = this.param.y;

		if(typeof this.param.title === 'string')
			this.setTitle(this.param.title);
		else
			this.setTitle(this.defaultTitle);
		
		this.onFocus();
		this.onResize();

		this._setEvents();
	},


	/**
	 * 各イベントを設定する
	 */
	_setEvents: function(){
		joEvent.addEvent($C('button-close', this.display.window), 'lclick', this.close, false, this);
		joEvent.addEvent($C('button-minimize', this.display.window), 'lclick', this.toggleMinimize, false, this);
		joEvent.addEvent($C('button-maximize', this.display.window), 'lclick', this.toggleMaximize, false, this);
		joEvent.addEvent($C('dammy-wrapper', this.display.window), 'mousedown', this.onFocus, false, this);
		joEvent.addEvent(this.display.window, 'joResize', this.onResize, false, this);
		joEvent.addEvent(this.display.window, 'joResizeEnd', this.onResize, false, this);
		joEvent.addEvent(this.display.window, 'mousedown', function(event){ event.stopPropagation(); }, false, this);
		joEvent.setDraggable(this.display.menubar, this.display.window, $('display'));
		joEvent.setResizable($C('resizer', this.display.window), this.display.window);
	},
	
	_setRelatedPosition: function(){
		if(typeof this.param.related === 'object' || (!this.param.x && !this.param.y) ){
			if(this.param.related){
				var node = this.param.related.display ? this.param.related.display.content : this.param.related;
			}else{
				var node = joAppManager.getFrontWindow();
			}
			
			if(!node) return;
			
			var rect = joCore.Node.getNodeRect(node);
			this.param.x = rect.left + 10;
			this.param.y = rect.top + 10;
		}
	},

	/**
	 * ウィンドウがリサイズされたときに呼び出される
	 */
	onResize: function(){
		this.display.content.style.height = ( this.display.statusbar.getBoundingClientRect().top - 
		                                      this.display.menubar.getBoundingClientRect().bottom  ) + 'px';
	},

	/**
	 * ウィンドウがフォーカスされたときに呼び出される
	 */
	onFocus: function(){
		this.updateZIndex(this.display.window);
		joAppManager.changeActiveApp(this.param.application || 'System');
	},

	/**
	 * ウィンドウを閉じる<br>
	 * 閉じたときに同じアプリケーションのウィンドウをアクティブにする
	 */
	close: function(){
		this.display.window.parentNode.removeChild(this.display.window);
		
		var shouldFront = (function(self){
			if(self.param.application){
				var tmp = joAppManager.getFrontWindow(self.param.application);
				return tmp ? tmp : joAppManager.getFrontWindow();
			}else{
				return joAppManager.getFrontWindow();
			}
		})(this);
		
		if(shouldFront) shouldFront.owner.onFocus();
	},

	/**
	 * 最小化/通常を切り替える
	 */
	toggleMinimize: function(){
		this.display.window.hasAttribute('minimized') ?
			this.display.window.removeAttribute('minimized') :
			this.display.window.setAttribute('minimized', 'true');
	},

	/**
	 * 最大化/通常を切り替える
	 */
	toggleMaximize: function(){
		this.display.window.hasAttribute('maximized') ?
			this.display.window.removeAttribute('maximized') :
			this.display.window.setAttribute('maximized', 'true');
	},

	/**
	 * ウィンドウをアクティブにする
	 * @param {Node} aActiveWindow アクティブにするウィンドウ
	 */
	updateZIndex: function(aActiveWindow){
		if(!joCore.Node.hasClass(aActiveWindow, 'window')) return;

		var activeWindow = joAppManager.getFrontWindow(), maxZ;
		
		if(activeWindow){
			activeWindow.removeAttribute('active');
			maxZ = activeWindow.style.zIndex;
		}else{
			maxZ = 0;
		}

		aActiveWindow.setAttribute('active', 'true');
		aActiveWindow.style.zIndex = Number(maxZ) + 1;
	},

	/**
	 * ウィンドウタイトルを設定する
	 * @param {String} aTitle タイトル
	 */
	setTitle: function(aTitle){
		this.display.title.innerHTML = aTitle;
	},
	
	/**
	 * ウィンドウの内容を設定する
	 * @param {DOM|Object} aContent 内容
	 * @return {DOM} this.display.content
	 */
	setContent: function(aContent){
		while(this.display.content.childNodes.length > 0)
			this.display.content.removeChild(this.display.content.firstChild);
		
		this.addContent(aContent);
	},

	/**
	 * ウィンドウの内容を追加する
	 * @param {DOM|Object} aContent 内容
	 * @return {DOM} this.display.content
	 */
	addContent: function(aContent){
		switch(typeof aContent){
			case 'object':
				this.display.content.appendChild(aContent);
				break;
				
			case 'string':
				this.display.content.innerHTML += aContent;
				break;
		}	
	},

};

/**
 * Create a dialog
 * @constructor
 * @extends joWindow
 * @param {String} param.message ダイアログに表示するメッセージ
 */
function joDialog(param){
	this.param = param;
	this.display = {};

	//指定がない場合は自動的に画面の中央に表示する
	if(!this.param.x && !this.param.y){
		this.param.x = joDisplay.displayWidth/2 - this.param.width/2;
		this.param.y = joDisplay.displayHeight/2 - this.param.height/2;
	}
	
	//大きさのデフォルト： 300x100
	if(!this.param.width) this.param.width = 300;
	if(!this.param.height) this.param.height = 100;

	this.init();
	this.init_self();
}
joDialog.prototype = {

	constract: [
		'<div class="menubar">',
		'	<button class="button-close">x</button>',
		'	<div class="title"></div>',
		'</div>',
		'<div class="content"></div>',
		'<div class="statusbar"></div>',
		'<div class="dammy-wrapper"></div>', //non-activeなwindowにかぶせ、clickを効率よく処理するためのwrapper
	].join(''),

	defaultTitle: '',
	
	/**
	 * joDialog独自の初期化処理
	 * @private
	 */
	init_self: function(){
		joCore.Node.addClass(this.display.window, 'dialog');
		joCore.Node.createNode('div', { 'class': 'message', ':child': this.param.message || '' }, this.display.content);
		joCore.Node.createNode('button', { 'class': 'button-ok', ':context': 'OK' }, this.display.content);
		
		if(typeof this.param.callback === 'function')
			joEvent.addEvent($C('button-ok', this.display.window), 'mousedown', this.param.callback, false, this, true);
		joEvent.addEvent($C('button-ok', this.display.window), 'lclick', this.close, false, this, true);
	},

	_setEvents: function(){
		joEvent.addEvent($C('button-close', this.display.window), 'lclick', this.close, false, this);
		joEvent.addEvent($C('dammy-wrapper', this.display.window), 'mousedown', this.onFocus, false, this);
		joEvent.addEvent(this.display.window, 'mousedown', function(event){ event.stopPropagation(); }, false, this);
		joEvent.setDraggable(this.display.menubar, this.display.window, $('display'));
	},
	
	onResize: function(){
		this.display.content.style.height = ( this.display.window.getBoundingClientRect().bottom - 
		                                      this.display.menubar.getBoundingClientRect().bottom  ) + 'px';
	},
};
joDialog.prototype.__proto__ = joWindow.prototype;